import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { cloneDeep } from '@/utils'
import { isFunction } from '@/utils/is'
import { CreateAxiosConfig, Result } from './type/AxiosTypes'

export type ErrorResult<T = any> = [error: string | null, data: T]
export type PageResult<T = any> = [error: string | null, data: { count: number; data: T }]

export class AnAxios {
  private _axios: AxiosInstance

  private readonly _options: CreateAxiosConfig
  constructor(config: CreateAxiosConfig) {
    this._options = config
    this._axios = axios.create(config)
    this.setupInterceptors()
  }

  public getAxios(): AxiosInstance {
    return this._axios
  }

  public createAxios(config: AxiosRequestConfig) {
    this._axios = axios.create(config)
  }

  public getTransform() {
    const { transform } = this._options
    return transform
  }

  public setupInterceptors() {
    const transform = this.getTransform()
    if (!transform) return

    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptorsCatch,
      responseInterceptors,
    } = transform

    this._axios.interceptors.request.use((config: AxiosRequestConfig) => {
      // const { headers } = config

      if (requestInterceptors && isFunction(requestInterceptors)) {
        config = requestInterceptors(config, this._options)
      }
      return config
    }, undefined)

    requestInterceptorsCatch &&
      isFunction(requestInterceptorsCatch) &&
      this._axios.interceptors.request.use(undefined, requestInterceptorsCatch)

    this._axios.interceptors.response.use((res: AxiosResponse<any>) => {
      if (responseInterceptors && isFunction(responseInterceptors)) {
        // @ts-ignore
        res = responseInterceptors(res)
      }
      return res
    }, undefined)

    responseInterceptorsCatch &&
      isFunction(responseInterceptorsCatch) &&
      this._axios.interceptors.response.use(undefined, responseInterceptorsCatch)
  }

  public get<T = any>(config: AxiosRequestConfig): Promise<ErrorResult<T>> {
    return this.request({ ...config, method: 'GET' })
  }

  public post<T = any>(config: AxiosRequestConfig): Promise<ErrorResult<T>> {
    if (config.data) {
      return this.request({ ...config, method: 'POST' })
    }
    return this.request({ ...config, method: 'POST', data: config.params, params: {} })
  }

  public request<T = any>(config: AxiosRequestConfig): Promise<ErrorResult<T>> {
    const conf: AxiosRequestConfig = cloneDeep(config)

    return new Promise((resolve, reject) => {
      this._axios
        .request<any, AxiosResponse<Result>>(conf)
        .then((res: AxiosResponse<Result>) => {
          // if (transformRequestHook && isFunction(transformRequestHook)) {
          //   try {
          //     const ret = transformRequestHook(res, opt);
          //     resolve(ret);
          //   } catch (err) {
          //     reject(err || new Error('request error!'));
          //   }
          //   return;
          // }
          resolve(res as unknown as Promise<ErrorResult>)
        })
        .catch((e: Error) => {
          // if (requestCatchHook && isFunction(requestCatchHook)) {
          //   reject(requestCatchHook(e, opt));
          //   return;
          // }
          reject(e)
        })
    })
  }
}
